﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text;
using Services.Contracts;
using System.Speech.Synthesis;
using System.Net;
using System.Web;
using NAudio.Wave;
using System.Threading.Tasks;
using System.Threading;

namespace Services.Implementation
{
    [Export(typeof(ISpeaker)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class Speaker : ISpeaker
    {
        readonly string _url = "http://translate.google.com/translate_tts?ie=UTF-8&q={0}&tl=de";
        private WaveOut _waveOut;
        private Task _speakTask;
        CancellationTokenSource _cancellationTokenSource;

        public Speaker()
        {
            _cancellationTokenSource = new CancellationTokenSource();
        }

        void ISpeaker.Speak(string paragraph)
        {
            var paragraphSplit = paragraph.Split(new char[6] { ',', '.', ';', '!', '?', ':' });

            if (_waveOut != null)
            {
                _waveOut.Stop();
                _cancellationTokenSource.Cancel();
            }
            _cancellationTokenSource = new CancellationTokenSource();
            _speakTask = new Task(() => SpeakAsync(paragraphSplit, _cancellationTokenSource.Token));
            _speakTask.Start();
        }

        private void SpeakAsync(string[] paragraphSplit, CancellationToken cancellationToken)
        {
            foreach (var sentence in paragraphSplit)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                if (sentence.Length > 70)
                {
                    PlayInChunks(sentence);
                }
                else
                {
                    MemoryStream file = DownloadFile(sentence);
                    PlayFile(file);
                }
            }
        }

        private void PlayInChunks(string sentence)
        {
            var sentenceSplit = sentence.Split(new char[1] { ' ' });
            int i = 0;

            while (i != sentenceSplit.Length)
            {
                int count = 0;
                sentence = string.Empty;

                for (; i < sentenceSplit.Length; i++)
                {
                    if (count + sentenceSplit[i].Length < 70)
                    {
                        sentence += sentenceSplit[i] + " ";
                        count += sentenceSplit[i].Length;
                    }
                    else
                    {
                        break;
                    }
                }

                MemoryStream file = DownloadFile(sentence);
                PlayFile(file);
            }
        }

        private MemoryStream DownloadFile(string phrase)
        {
            MemoryStream ms = null;
            var address = string.Format(_url, HttpUtility.UrlEncode(phrase));

            using (WebClient client = new WebClient())
            {
                byte[] arr = client.DownloadData(address);
                ms = new MemoryStream(arr);
            }

            return ms;
        }

        private void PlayFile(MemoryStream ms)
        {
            using (WaveStream blockAlignedStream = new Mp3FileReader(ms))
            {
                using (_waveOut = new WaveOut())
                {
                    bool play = true;
                    _waveOut.Init(blockAlignedStream);
                    _waveOut.PlaybackStopped += (sender, eventArgs) => { play = false; };
                    _waveOut.Play();

                    while (play)
                    {
                        System.Threading.Thread.Sleep(100);
                    }
                }
            }
        }
    }
}